/** 
* @file        xy_net_api.h
* @brief       tcpip api,dns/socket/ping...
*
* @attention  User must use these APIs in the right process,and prevent state inconsistency caused by instantaneous change

* @warning     Socket related, please see lwip  POSIX Socket API "sockets.h"
*
*/
#pragma once
#include <stdint.h>
#include "lwip/ip_addr.h"
#include "lwip/inet.h"

/*******************************************************************************
 *                             Macro definitions                               *
 ******************************************************************************/
#define IPADDR_LEN 16

/*******************************************************************************
 *                             Type definitions                                *
 ******************************************************************************/
/**
 * @brief ipv4 数据
 */
typedef struct PsNetifIpv4Info_T
{
	ip4_addr_t ip;
	ip4_addr_t gateway;
	ip4_addr_t pri_dns;
	ip4_addr_t sec_dns;
} PsNetifIpv4Info;

/**
 * @brief ipv6 数据
 */
typedef struct PsNetifIpv6Info_T
{
	unsigned char addr_type;
	unsigned char addr_stats;
	unsigned short mtu;
	unsigned short hop_limit;
	unsigned int base_reachable_time;
	unsigned int reachable_time;
	unsigned int retrans_timer;
	struct in6_addr ipv6_addr;
} PsNetifIpv6Info;

/**
 * @brief ip类型定义
 */
typedef enum PsNetifIpType_T
{
    NON_IP,
    IPV4_TYPE,
    IPV6_TYPE,
    IPV46_TYPE,
} PsNetifIpType;

/**
 * @brief Netif状态事件定义
 */
typedef enum PsNetifStateChangeEvent_T
{
    EVENT_PSNETIF_CELLACCESS             = 1 << 0, //小区驻留成功,仅上报状态，获取ps具体信息请调用ps相关接口
    EVENT_PSNETIF_ENTER_OOS              = 1 << 1, //OOS状态，小区驻留失败
    EVENT_PSNETIF_ENTER_IS               = 1 << 2, //从OOS进入IS
    EVENT_PSNETIF_DEACTIVATED            = 1 << 3, //NEITF未激活
    EVENT_PSNETIF_ACTIVATED              = 1 << 4, //NEITF已激活
    EVENT_PSNETIF_ACTIVATED_INFO_CHNAGED = 1 << 5, //NEITF已激活状态下,网卡信息发生改变，如dns server变化
    EVENT_PSNETIF_IPV6_ADDR_PREFERED     = 1 << 6, //NEITF已激活状态下,网卡信息发生改变，如dns server变化
    EVENT_PSNETIF_ALL_MASK = (EVENT_PSNETIF_CELLACCESS | EVENT_PSNETIF_ENTER_OOS | EVENT_PSNETIF_ENTER_IS |
                              EVENT_PSNETIF_DEACTIVATED | EVENT_PSNETIF_ACTIVATED | 
                              EVENT_PSNETIF_IPV6_ADDR_PREFERED | EVENT_PSNETIF_ACTIVATED_INFO_CHNAGED),
} PsNetifStateChangeEvent;

/**
 * @brief netif info数据
 */
typedef struct PsNetifInfo_T
{
    uint8_t           ipType;               //see @ref PsNetifIpType
    uint8_t           workingCid;           //pdp channel id
    uint16_t          reserved;
    PsNetifIpv4Info   ipv4Info;
    PsNetifIpv6Info   ipv6Info;
} PsNetifInfo;

/**
 * @brief psnetif事件回调接口类型定义
 * @param eventId  用户需要监听的psnetif事件 @see @ref PsNetifStateChangeEvent
 * @warning 注册psnetif回调函数必须在系统初始化中执行，否则可能出现事件遗漏问题 
 */
typedef int32_t (*psNetifEventCallback_t)(uint32_t eventId);

/*******************************************************************************
 *                       Global function declarations                          *
 ******************************************************************************/
/**
 * @brief  set IPV4 dns server,and will save into NV
 * @ingroup tcpipapi
 * @param pridns   first DNS server,32 bit
 * @param secdns   second DNS server,32 bit
 * @return bool,see @ref  xy_ret_Status_t
 * @note  输入的IP地址为二进制网络字节序
 */
int xy_dns_set(ip4_addr_t *pridns,ip4_addr_t *secdns);

/**
 * @brief  set IPV4 dns server,and will save into NV
 * @ingroup tcpipapi
 * @param pri_dns   first DNS server,such as "114.114.114.114"
 * @param sec_dns   second DNS server,such as "114.114.114.114"
 * @return bool,see  @ref xy_ret_Status_t
 * @note   输入的IP地址为点分文本的IP地址，内部通过inet_pton接口转换为二进制网络字节序的IP地址
 */
int xy_dns_set2(char *pri_dns,char *sec_dns);

/**
 * @brief  阻塞等待PDP激活成功和TCPIP网路成功。由于平台内部串行处理，在收到“+CGEV: ME PDN ACT 0”时，tcpip协议栈的网路尚未配置完成，此时调用该接口时入参不能为0
 * 
 * @param timeout  0，非阻塞态，立即返回
 * @return  bool,see  @ref  xy_ret_Status_t
 * @attention  用户需要特别注意超时时间，一旦超时，表明3GPP无线环境异常，建议客户软重启后再尝试，若多次失败，建议睡眠一段时间后再尝试. \n
 *  若用户在开机后直接调用该接口，建议timeout设置大于30秒，以给3GPP足够的时长进行小区驻留。
 */
int xy_wait_tcpip_ok(int timeout);

/**
 * @brief 			This is funtion user get IP Addr
 * @param ipAddr	由调用者申请内存，接口内部赋值
 * @param addrLen	入参ipAddr指针的长度，由调用者赋值，但不能小于17 
 * @return 			XY_ERR is fail,XY_OK is success.
 * @warning         注意入参内存申请长度，否则会造成内存越界
 *                  若尚未PDP激活成功，ipAddr不会被赋值
 * @note            该接口得到的是字符串类型地址，如需要转成int型，需要自行调用inet_aton接口
 */
int xy_getIP4Addr(char *ipAddr, int addrLen);

/**
 * @brief 			获取IPV4的整形地址
 * @param 			存储ip4addr的unsigned int指针
 * @return			XY_ERR获取失败, XY_OK获取成功
 * @warning         若尚未PDP激活成功，返回XY_ERR
 */
int xy_get_ip4addr(unsigned int *ip4addr);

/**
 * @brief 获取网络信息，如ip地址，地址类型等
 * @param netifInfo [OUT] 返回给用户的netfinfo数据，内存由用户申请
 * @return XY_ERR: 网卡尚未激活或者netifInfo参数为NUL, XY_OK:执行成功
 * @note
 */
int xy_get_netifInfo(PsNetifInfo *netifInfo);

/**
 * @brief 用户注册netif事件回调接口
 * @param  eventGroup  用户需要监听的事件组，可以是多个事件组合，也可以是单个事件
 * @param  callback 回调接口，类型@see @ref psNetifEventCallback_t
 * @warning 注册用户回调必须在初始化过程中完成！
 */
void xy_regist_psnetif_callback(uint32_t eventGroup, psNetifEventCallback_t callback);

/**
 * @brief 用户获取有效的ipv6地址
 * @param  ip6addr[OUT] 用户给定的返回地址
 * @return XY_ERR:netif网卡尚未激活/参数错误/未拿到有效的Ipv6单播地址
 * @note 用户给定的返回地址需预留至少16个字节
 */
int xy_get_ip6addr(unsigned int *ip6addr);

/**
 * @brief  用户根据ip类型获取对应的ip地址
 * @param  ipType ipv4/v6 
 * @param  ipaddr 
 * @return XY_ERR:netif网卡尚未激活/参数错误/未拿到有效的Ip地址
 * @note
 */
int xy_get_ipaddr(unsigned int ipType, unsigned int *ipaddr);

/**
 * @brief 获取PDP激活的IP类型
 * @return 返回ip类型see @ref PsNetifIpType
 * @note 该接口需要在pdp激活后调用
 */
uint8_t xy_get_netifIpType(void);
